<html><head>
    <title>Image Gauge</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link rel="stylesheet" href="{{ STATIC_URL }}css/webgl.css" type="text/css">
    <script src="{{ STATIC_URL }}jsp/gl-matrix.js" type="text/javascript"></script>  
    <script src="{{ STATIC_URL }}jsp/sylvester.js" type="text/javascript"></script>
    <script src="{{ STATIC_URL }}jsp/glUtils.js" type="text/javascript"></script>
    <script src="{{ STATIC_URL }}jsp/sampleItem.js" type="text/javascript"></script>
    
    
    <script tyep = "text/javascript">
		
	var STATIC_URL = "{{ STATIC_URL }}";
		
	var canvas;
	var gl;
	var midImageFile = STATIC_URL + "images/practice_s1/mid.png" 
	
	var webglImageShader = null;
	var gaugeShader = null;
	var sampleItem = null;
	
	//input data		
	var gaugeGroundTruth = [
			[347, 95, 76, 37, 45, 164],
			[561, 98, 109, 64, 22, 93],
			[649, 179, 68, 44, 36, 95],
			[388, 208, 39, 13, 80, 155],
			[344, 296, 44, 32, 135, 211],
			[328, 216, 53, 37, 111, 215],
			[560, 241, 33, 23, 56, 111],
			[510, 171, 54, 37, 40, 106],
			[491, 299, 21, 2, 105, 135],
			[419, 383, 33, 20, 179, 171],
			[336, 421, 78, 63, 194, 214],
			[551, 429, 49, 58, 228, 93],
			[567, 364, 24, 12, 176, 104],
			[692, 307, 44, 37, 153, 41],
			[655, 236, 44, 28, 57, 90],
			[478, 213, 36, 23, 55, 117],
			[437, 115, 71, 40, 38, 100],
			[409, 267, 29, 7, 104, 163],
			[616, 311, 25, 6, 117, 90],
			[464, 434, 45, 41, 220, 137]
			];
	var sampleIndex = 0;
	var depthResize = 0.25;
	var depthOffset = -6.0;
	var focalLength = 35;
	var sensorWidth = 32;
	var sensorHeight = 18;
	var MouseState = {
		STILL : 0,
		MOVING : 1
	};
	var ReferenceState = {
		PRACTICE: 0,
		SHOW_GROUNDTRUTH : 1
	};
	
	var currentMouseState = 0;
	var currentReferenceState = 0;    	 
	
	//mouse and keyboard handler
	function handleMouseDown(e)
	{
		var mx = e.clientX;
		var my = e.clientY;
		
		if(sampleItem)
		{
			currentMouseState = MouseState.MOVING;
			sampleItem.flipSlant();
			sampleItem.setRotationAngleFromMousePosition(mx, my);
		}	
	}
	function handleMouseUp(e)
	{
		currentMouseState = MouseState.STILL;		
	}
	function handleMouseMove(e)
	{
		var mx = e.clientX;
		var my = e.clientY;
		if(sampleItem && currentMouseState == MouseState.MOVING)
		{			
			sampleItem.setRotationAngleFromMousePosition(mx, my);
		}		
	}
	function handleKeyboard(event)
	{
		keyCode = event.keyCode;
		if(keyCode == 32) //space
		{
			if(currentReferenceState == ReferenceState.PRACTICE)
			{
				currentReferenceState = ReferenceState.SHOW_GROUNDTRUTH;
			}
			else if(currentReferenceState == ReferenceState.SHOW_GROUNDTRUTH)
			{
				currentReferenceState = ReferenceState.PRACTICE;
				sampleIndex += 1;
			    sampleIndex %= gaugeGroundTruth.length;			 
			    var nb = gaugeGroundTruth[sampleIndex][3];
			    var ng = gaugeGroundTruth[sampleIndex][4];
			    var nr = gaugeGroundTruth[sampleIndex][5];	 	 	 
			    var n = calcNormalFromPixel(nr, ng, nb);
			  
			    sampleItem.setGroundTruthNormal(n);
			  
			  
			    //move to current position  
			    var x = gaugeGroundTruth[sampleIndex][0];
			    var y = gaugeGroundTruth[sampleIndex][1];
			    var depth255 = gaugeGroundTruth[sampleIndex][2];
			    var pos = calcPosition(x, y, depth255)	  
			  
			    sampleItem.setCenter(x, y);
			    sampleItem.setGroundTruthPosition(pos);				
			}
			if (event.preventDefault)
			{
				
				event.preventDefault();
				event.returnValue = false;
			}		  		  				
		}	
	}
	
	function handleMouseWheel(event)
	{
		var delta = 0;
		if (!event) /* For IE. */
		{
			event = window.event;
		}
		if (event.wheelDelta) { /* IE/Opera. */
			delta = event.wheelDelta/120;
		} else if (event.detail)
		{ /** Mozilla case. */
		/** In Mozilla, sign of delta is different than in IE.
		* Also, delta is multiple of 3.
		*/
			delta = -event.detail/3;
		}
		/** If delta is nonzero, handle it.
		* Basically, delta is now positive if wheel was scrolled up,
		* and negative, if wheel was scrolled down.
		*/
		if (delta)
		{		
			if(delta < 0)
			{
				sampleItem.decreaseSlant();
			}
			else
			{
				sampleItem.addSlant();
			}
		}
		/** Prevent default actions caused by mouse wheel.
		* That might be ugly, but we handle scrolls somehow
		* anyway, so don’t bother here..
		*/
		if (event.preventDefault)
		{
			
			event.preventDefault();
			event.returnValue = false;
		}		
	}
	
	
	function start() 
	{
	  canvas = document.getElementById("glcanvas");

	  initWebGL();      // Initialize the GL context	  
	  
	  // Only continue if WebGL is available and working
	  canvas.onmousedown = handleMouseDown;	 
	  canvas.onmouseup = handleMouseUp;
	  canvas.onmousemove = handleMouseMove;
	  document.onkeydown = handleKeyboard;
	  
	  if (canvas.addEventListener)
	  {
		  canvas.addEventListener('DOMMouseScroll', handleMouseWheel, false);
	  }
	  
	  if (gl) 
	  {
		gl.clearColor(0.0, 0.0, 0.0, 1.0);  // Clear to black, fully opaque
		gl.clearDepth(1.0);                 // Clear everything
		gl.enable(gl.DEPTH_TEST);           // Enable depth testing
		gl.depthFunc(gl.LEQUAL);            // Near things obscure far things
		
		// Initialize the shaders; this is where all the lighting for the
		// vertices and so forth is established.
		
		webglImageShader = new WebGLImageShader();
		gaugeShader = new WebGLGaugeShader();
		sampleItem = new SampleItem();
		
		// Here's where we call the routine that builds all the objects
		// we'll be drawing.
	
		webglImageShader.initBuffers(gl);	
		gaugeShader.initGaugeBuffers(gl);
		
		webglImageShader.initShaders(gl, "shader-vs-image", "shader-fs-image");
		gaugeShader.initShaders(gl, "shader-vs-gauge", "shader-fs-gauge");
		
		// Next, load and set up the textures we'll be using.
		
		//cubetexture.png random_obj_1/left/Image0001.png  desktop.png
		
		// Set up to draw the scene periodically.
		initTextures(midImageFile);
		
		initSampleItem();	
		
		setInterval(drawScene, 15);
	  }
	  else
	  {
		  alert("can't initWebGL. Please enable WegGL in your browser.");
	  }
	}
	
	
	//
	// initWebGL
	//
	// Initialize WebGL, returning the GL context or null if
	// WebGL isn't available or could not be initialized.
	//
	function initWebGL()
	{
	  gl = null;
	  
	  try {
		gl = canvas.getContext("experimental-webgl");
	  }
	  catch(e) {
	  }
	  
	  // If we don't have a GL context, give up now
	  
	  if (!gl) {
		alert("Unable to initialize WebGL. Your browser may not support it.");
	  }
	}	
	
	function initSampleItem()
	{
		//init the first garge position, normal		
		var nb = gaugeGroundTruth[sampleIndex][3];
		var ng = gaugeGroundTruth[sampleIndex][4];
		var nr = gaugeGroundTruth[sampleIndex][5];	 	 	 
		var n = calcNormalFromPixel(nr, ng, nb);
		  
		sampleItem.setGroundTruthNormal(n);	  
	  
	  
		  //move to current position  
		var x = gaugeGroundTruth[sampleIndex][0];
		var y = gaugeGroundTruth[sampleIndex][1];
		var depth255 = gaugeGroundTruth[sampleIndex][2];
		var pos = calcPosition(x, y, depth255)	  
	  
		sampleItem.setCenter(x, y);
		sampleItem.setGroundTruthPosition(pos);		
	}
	
	
	function drawScene()
	{
		webglImageShader.drawImage(gl);
		drawGauge();
	}
	
	function calcPosition(x, y, depth255)
	{		
		var h = canvas.height;
		var w = canvas.width;
		var px = x, py = y, pz;
		var pz = depth255/255.0 * depthResize - depthOffset;
		var ratio = w/sensorWidth;
		var fc = focalLength * ratio;
		
		//reverse y since y = 0 in left top corner of windows
		y = h - y;
		
		var dir = vec3.fromValues(x - w/2, y - h/2, fc);		
		vec3.normalize(dir, dir);		
		var scale = pz/dir[2];
		vec3.scale(dir, dir, scale);
		
		dir[2] = - dir[2];		
		return dir;	
	}
	
	function calcNormalFromPixel(nr, ng, nb)
	{
		//pixel to normal
		var nx, ny, nz;
		nx = nr/255.0;
		ny = ng/255.0;
		nz = nb/255.0;
		
		nx = (nx - 0.5) * 2.0;
		ny = (ny - 0.5) * 2.0;
		nz = (nz - 0.5) * 2.0;		
		
		var n = vec3.fromValues(-nx, -ny, nz);
		vec3.normalize(n, n);	
		return n;		
	}
	
	function calcRotationMatrixFromNormal(n)
	{
		var nx = n[0];
		var ny = n[1];
		var nz = n[2];
		var theta = Math.PI - Math.acos(nz);		
		var phi = Math.atan2(ny, nx);
		
		
		var rY = mat4.create();
		var rZ = mat4.create();
		var rMatrix = mat4.create();
		mat4.identity(rY);
		mat4.identity(rZ);
				
        mat4.rotateY(rY, rY, theta);
        mat4.rotateZ(rZ, rZ, phi);
        mat4.multiply(rMatrix, rZ, rY);  //order
        return rMatrix; 
	}

	
	function drawGauge()
	{
		// Clear the canvas before we start drawing on it.

	  gl.clear(gl.DEPTH_BUFFER_BIT);
	  gl.useProgram(gaugeShader.shaderProgram);
	  
	  // Establish the perspective with which we want to view the
	  // scene. Our field of view is 45 degrees, with a width/height
	  // ratio of 640:480, and we only want to see objects between 0.1 units
	  // and 100 units away from the camera.
	  
	  var perspectiveMatrix = mat4.create();
	  var modelMatrix = mat4.create();
	  var mvMatrix = mat4.create();
	  mat4.identity(perspectiveMatrix);
	  mat4.identity(modelMatrix);
	  mat4.identity(mvMatrix);
	  
	  //28.83 = atan(9.0/35.0)*2
	  var fovy = Math.atan(sensorHeight/2/focalLength) * 2;
	  
	  mat4.perspective(perspectiveMatrix, fovy, canvas.width/canvas.height, 0.1, 100.0); 
	   
	  
	//  var n = sampleItem.getGroundTruthNormal();
	  var fixSlant = document.getElementById("idfixSlantAngle").checked;
	  var fixRotation = document.getElementById("idfixRotationAngle").checked;
	  var n = sampleItem.getNormalFree();
	  if(fixSlant)
	  {
		  n = sampleItem.getNormalWithSlant(); //with groundtruth slant angle		  
	  }
	  if(fixRotation)
	  {
		  n = sampleItem.getNormalWithRotation();
	  }
	  
	  if(fixSlant && fixRotation)
	  {
		  n = sampleItem.getGroundTruthNormal();
	  }
	  
	  var rotateMatrix = calcRotationMatrixFromNormal(n);	
	
	  var pos = sampleItem.getPosition();  
	  
	  var translateMatrix = mat4.create();
	  mat4.identity(translateMatrix, translateMatrix);
	  mat4.translate(translateMatrix, translateMatrix, pos);	 
	 
	  mat4.multiply(mvMatrix, translateMatrix, rotateMatrix); 
	  
	  var viewMatrix = mat4.create();
	  var eye    = vec3.fromValues(0, 0, 0);
	  var center = vec3.fromValues(0, 0, -10);
	  var up = vec3.fromValues(0, 1, 0);
	  mat4.lookAt(viewMatrix, eye, center, up);
	  
	  mat4.multiply(mvMatrix, viewMatrix, mvMatrix);
	  
	  var color = vec3.fromValues(1.0, 0.0, 0);
	  var scale = vec3.fromValues(1.0, 1.0, 1.0);
	  setMatrixUniforms(gaugeShader.shaderProgram, perspectiveMatrix, mvMatrix);
	  setColorUniform(gaugeShader.shaderProgram, color);
	  setScaleUniform(gaugeShader.shaderProgram, scale);
	  
	  //draw torus
	  gl.bindBuffer(gl.ARRAY_BUFFER, gaugeShader.verticesBuffer);
	  gl.vertexAttribPointer(gaugeShader.vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);	   
	  gl.drawArrays(gl.TRIANGLE_STRIP, 0, (72+2)*2);
	  
	  //draw stick
	  gl.bindBuffer(gl.ARRAY_BUFFER, gaugeShader.stickVerticesBuffer);
	  gl.vertexAttribPointer(gaugeShader.vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);	   
	  gl.drawArrays(gl.TRIANGLE_STRIP, 0, (72+2)*2); 
	  
	  //draw ground truth
	  if(currentReferenceState == ReferenceState.SHOW_GROUNDTRUTH)
	  {
		  n = sampleItem.getGroundTruthNormal(); //with groundtruth slant angle
	  
		  rotateMatrix = calcRotationMatrixFromNormal(n);			
		  pos = sampleItem.getPosition();  		  
		 
		  mat4.identity(translateMatrix, translateMatrix);
		  mat4.translate(translateMatrix, translateMatrix, pos); 
		 
		  mat4.multiply(mvMatrix, translateMatrix, rotateMatrix); 	  		  
		  
		  mat4.multiply(mvMatrix, viewMatrix, mvMatrix);  //viewMatrix is fixed
		  color = vec3.fromValues(0.0, 1.0, 0);           //draw groundtruth with different color and scale
		  scale = vec3.fromValues(0.8, 0.8, 0.8);
	      setMatrixUniforms(gaugeShader.shaderProgram, perspectiveMatrix, mvMatrix);
	      setColorUniform(gaugeShader.shaderProgram, color);
	      setScaleUniform(gaugeShader.shaderProgram, scale);
	  
			//draw torus
	      gl.bindBuffer(gl.ARRAY_BUFFER, gaugeShader.verticesBuffer);
		  gl.vertexAttribPointer(gaugeShader.vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);	   
		  gl.drawArrays(gl.TRIANGLE_STRIP, 0, (72+2)*2);
	  
			//draw stick
	      gl.bindBuffer(gl.ARRAY_BUFFER, gaugeShader.stickVerticesBuffer);
	      gl.vertexAttribPointer(gaugeShader.vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);	   
	      gl.drawArrays(gl.TRIANGLE_STRIP, 0, (72+2)*2);		  
	  }
	  	 
	}	
	
	function initTextures(imageName)
	{
		webglImageShader.imageTexture = gl.createTexture();
		webglImageShader.image = new Image();
		webglImageShader.image.onload = function()
		{
			handleTextureLoaded(webglImageShader.image, webglImageShader.imageTexture);
		}  //set callback function
		webglImageShader.image.src = imageName;		
	}
	
	function handleTextureLoaded(image, texture)
	{
		gl.bindTexture(gl.TEXTURE_2D, texture);  //set current texture
		
		//set the parameters so we can render any size image.
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
		
		gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);		
		gl.bindTexture(gl.TEXTURE_2D, null); //set current texture null	
	} 	
    </script>
    
    <script src="{{ STATIC_URL }}jsp/imageShaderUtils.js" type="text/javascript"></script>
    <script src="{{ STATIC_URL }}jsp/gaugeShaderUtils.js" type="text/javascript"></script>
    <script src="{{ STATIC_URL }}jsp/shaderUtils.js" type="text/javascript"></script>   
    
    <!-- Image Vertex shader program -->    
    <script id="shader-vs-image" type="x-shader/x-vertex">
	  //uniform: not change value
	  //attribute: in vertex shader
	  //varying: from vertex to fragment
      attribute vec2 a_position;
      attribute vec2 a_texCoord;
      varying vec2 v_texCoord;
      uniform vec2 u_resolution;    
      void main(void) {
		  vec2 zeroToOne = a_position /u_resolution;
		  vec2 zeroToTwo = zeroToOne * 2.0;
		  vec2 clipSpace = zeroToTwo - 1.0;		   
          gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
          v_texCoord = a_texCoord;
      }
    </script>
    
    <!-- Fragment shader program -->
    <script id="shader-fs-image" type="x-shader/x-fragment">
		precision mediump float;
		uniform sampler2D u_image;
		varying vec2 v_texCoord;
      
        void main(void)
        {
			gl_FragColor = texture2D(u_image, v_texCoord);
		}
    </script>
    
    <!-- Gauge Shader -->
    <!-- Vertex shader program -->
    
    <script id="shader-vs-gauge" type="x-shader/x-vertex">
      attribute vec3 aVertexPosition;
  //    attribute vec4 aVertexColor;
    
      uniform mat4 uMVMatrix;
      uniform mat4 uPMatrix;
      uniform vec3 scale;
      uniform vec3 color;
      
	  varying lowp vec4 vColor;
    
      void main(void) {		
        gl_Position = uPMatrix * uMVMatrix * vec4(scale * aVertexPosition, 1.0);
        //vColor = vec4(1.0, 0.0, 0.0, 1.0);
        vColor = vec4(color, 1.0);
      }
    </script>
    
    <!-- Fragment shader program -->
    <script id="shader-fs-gauge" type="x-shader/x-fragment">
    	varying lowp vec4 vColor;
    	
      void main(void) {
        gl_FragColor = vColor;
      }
    </script>
    
    
    
    
    
  </head>
  
  <body onload="start()">	
    <canvas id="glcanvas" width="960" height="540">
      Your browser doesn't appear to support the HTML5 <code>&lt;canvas&gt;</code> element.
    </canvas>
    
    <br>
    <input id="idfixSlantAngle" checked="checked" type="checkbox"> Fix Slant Angle <br>
    Press and hold left button of mouse to drage gauge to the surface normal direction.
    <br>
    
    <input id="idfixRotationAngle" type="checkbox"> Fix Rotation Angle <br>
    Rotate middle button of mouse to adjust the gauge to the surface normal direction.
    <br>    
   
    <br>
    <p>
	Step 1. Click and hold the left button of mouse, rotate the (red) gauge until it point to the direction of the surface normal. <br>
	Step 2. Press space bar in keyboard to show the ground truth of the gauge orientation(in green color). <br>
	Step 3. Press space bar to continue the practice. <br>
	</p>
	
	<p>
	How to enable WebGL: <br>
	FireFox: <a href = "http://www.ubuntuvibes.com/2012/03/how-to-enable-webgl-in-firefox-for.html"> FireFox Enable WebGL</a> <br>
	Safari: <a href = "https://discussions.apple.com/thread/3300585?start=0&tstart=0"> Safari Enable WebGL</a> <br>
	<p>
  
</body></html>
